{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/husein/.local/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:516: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
      "/home/husein/.local/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:517: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
      "/home/husein/.local/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:518: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
      "/home/husein/.local/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:519: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
      "/home/husein/.local/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:520: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
      "/home/husein/.local/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:525: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n",
      "/home/husein/.local/lib/python3.6/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:541: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
      "/home/husein/.local/lib/python3.6/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:542: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
      "/home/husein/.local/lib/python3.6/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:543: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
      "/home/husein/.local/lib/python3.6/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:544: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
      "/home/husein/.local/lib/python3.6/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:545: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
      "/home/husein/.local/lib/python3.6/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:550: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "import matplotlib.pyplot as plt\n",
    "from skimage.transform import resize as imresize\n",
    "import cv2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pickle\n",
    "\n",
    "with open('jawi-to-malay-dataset.pkl', 'rb') as fopen:\n",
    "    dataset = pickle.load(fopen)\n",
    "    \n",
    "train_X = dataset['train_X']\n",
    "train_labels = dataset['train_Y']\n",
    "test_X = dataset['test_X']\n",
    "test_labels = dataset['test_Y']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(train_X[-1])\n",
    "plt.title(train_labels[-1])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "charset = list(set(''.join(train_labels + test_labels)))\n",
    "num_classes = len(charset) + 2\n",
    "encode_maps = {}\n",
    "decode_maps = {}\n",
    "for i, char in enumerate(charset, 3):\n",
    "    encode_maps[char] = i\n",
    "    decode_maps[i] = char\n",
    "    \n",
    "SPACE_INDEX = 0\n",
    "SPACE_TOKEN = '<PAD>'\n",
    "encode_maps[SPACE_TOKEN] = SPACE_INDEX\n",
    "decode_maps[SPACE_INDEX] = SPACE_TOKEN\n",
    "\n",
    "GO_INDEX = 1\n",
    "GO_TOKEN = '<GO>'\n",
    "encode_maps[GO_TOKEN] = GO_INDEX\n",
    "decode_maps[GO_INDEX] = GO_TOKEN\n",
    "\n",
    "EOS_INDEX = 2\n",
    "EOS_TOKEN = '<EOS>'\n",
    "encode_maps[EOS_TOKEN] = EOS_INDEX\n",
    "decode_maps[EOS_INDEX] = EOS_TOKEN"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{3: 'h',\n",
       " 4: 'q',\n",
       " 5: 'l',\n",
       " 6: 'r',\n",
       " 7: 'x',\n",
       " 8: 'u',\n",
       " 9: 'i',\n",
       " 10: 't',\n",
       " 11: 'p',\n",
       " 12: \"'\",\n",
       " 13: 'y',\n",
       " 14: 'c',\n",
       " 15: 'b',\n",
       " 16: 'm',\n",
       " 17: ' ',\n",
       " 18: 'n',\n",
       " 19: 'z',\n",
       " 20: 'a',\n",
       " 21: 's',\n",
       " 22: 'v',\n",
       " 23: 'o',\n",
       " 24: '?',\n",
       " 25: 'e',\n",
       " 26: 'w',\n",
       " 27: 'j',\n",
       " 28: 'g',\n",
       " 29: 'd',\n",
       " 30: 'k',\n",
       " 31: 'f',\n",
       " 32: '-',\n",
       " 0: '<PAD>',\n",
       " 1: '<GO>',\n",
       " 2: '<EOS>'}"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "decode_maps"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[6, 20, 10, 20, 11, 20, 18, 2]"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[encode_maps[c] for c in train_labels[0]] + [2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "GO = 1\n",
    "PAD = 0\n",
    "EOS = 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "image_height = 60\n",
    "image_width = 240\n",
    "image_channel = 1\n",
    "max_stepsize = 128\n",
    "num_hidden = 256\n",
    "epoch = 20\n",
    "batch_size = 128\n",
    "initial_learning_rate = 1e-4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_Y = []\n",
    "for label in train_labels:\n",
    "    train_Y.append([encode_maps[c] for c in label] + [EOS])\n",
    "    \n",
    "test_Y = []\n",
    "for label in test_labels:\n",
    "    test_Y.append([encode_maps[c] for c in label] + [EOS])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# https://github.com/guillaumegenthial/im2latex/blob/master/model/components/attention_mechanism.py\n",
    "\n",
    "class AttentionMechanism(object):\n",
    "    \"\"\"Class to compute attention over an image\"\"\"\n",
    "\n",
    "    def __init__(self, img, dim_e, tiles=1):\n",
    "        \"\"\"Stores the image under the right shape.\n",
    "        We loose the H, W dimensions and merge them into a single\n",
    "        dimension that corresponds to \"regions\" of the image.\n",
    "        Args:\n",
    "            img: (tf.Tensor) image\n",
    "            dim_e: (int) dimension of the intermediary vector used to\n",
    "                compute attention\n",
    "            tiles: (int) default 1, input to context h may have size\n",
    "                    (tile * batch_size, ...)\n",
    "        \"\"\"\n",
    "        if len(img.shape) == 3:\n",
    "            self._img = img\n",
    "        elif len(img.shape) == 4:\n",
    "            N    = tf.shape(img)[0]\n",
    "            H, W = tf.shape(img)[1], tf.shape(img)[2] # image\n",
    "            C    = img.shape[3].value                 # channels\n",
    "            self._img = tf.reshape(img, shape=[N, H*W, C])\n",
    "        else:\n",
    "            print(\"Image shape not supported\")\n",
    "            raise NotImplementedError\n",
    "\n",
    "        # dimensions\n",
    "        self._n_regions  = tf.shape(self._img)[1]\n",
    "        self._n_channels = self._img.shape[2].value\n",
    "        self._dim_e      = dim_e\n",
    "        self._tiles      = tiles\n",
    "        self._scope_name = \"att_mechanism\"\n",
    "\n",
    "        # attention vector over the image\n",
    "        self._att_img = tf.layers.dense(\n",
    "            inputs=self._img,\n",
    "            units=self._dim_e,\n",
    "            use_bias=False,\n",
    "            name=\"att_img\")\n",
    "\n",
    "\n",
    "    def context(self, h):\n",
    "        \"\"\"Computes attention\n",
    "        Args:\n",
    "            h: (batch_size, num_units) hidden state\n",
    "        Returns:\n",
    "            c: (batch_size, channels) context vector\n",
    "        \"\"\"\n",
    "        with tf.variable_scope(self._scope_name):\n",
    "            if self._tiles > 1:\n",
    "                att_img = tf.expand_dims(self._att_img, axis=1)\n",
    "                att_img = tf.tile(att_img, multiples=[1, self._tiles, 1, 1])\n",
    "                att_img = tf.reshape(att_img, shape=[-1, self._n_regions,\n",
    "                        self._dim_e])\n",
    "                img = tf.expand_dims(self._img, axis=1)\n",
    "                img = tf.tile(img, multiples=[1, self._tiles, 1, 1])\n",
    "                img = tf.reshape(img, shape=[-1, self._n_regions,\n",
    "                        self._n_channels])\n",
    "            else:\n",
    "                att_img = self._att_img\n",
    "                img     = self._img\n",
    "\n",
    "            # computes attention over the hidden vector\n",
    "            att_h = tf.layers.dense(inputs=h, units=self._dim_e, use_bias=False)\n",
    "\n",
    "            # sums the two contributions\n",
    "            att_h = tf.expand_dims(att_h, axis=1)\n",
    "            att = tf.tanh(att_img + att_h)\n",
    "\n",
    "            # computes scalar product with beta vector\n",
    "            # works faster with a matmul than with a * and a tf.reduce_sum\n",
    "            att_beta = tf.get_variable(\"att_beta\", shape=[self._dim_e, 1],\n",
    "                    dtype=tf.float32)\n",
    "            att_flat = tf.reshape(att, shape=[-1, self._dim_e])\n",
    "            e = tf.matmul(att_flat, att_beta)\n",
    "            e = tf.reshape(e, shape=[-1, self._n_regions])\n",
    "\n",
    "            # compute weights\n",
    "            a = tf.nn.softmax(e)\n",
    "            a = tf.expand_dims(a, axis=-1)\n",
    "            c = tf.reduce_sum(a * img, axis=1)\n",
    "\n",
    "            return c\n",
    "\n",
    "\n",
    "    def initial_cell_state(self, cell):\n",
    "        \"\"\"Returns initial state of a cell computed from the image\n",
    "        Assumes cell.state_type is an instance of named_tuple.\n",
    "        Ex: LSTMStateTuple\n",
    "        Args:\n",
    "            cell: (instance of RNNCell) must define _state_size\n",
    "        \"\"\"\n",
    "        _states_0 = []\n",
    "        for hidden_name in cell._state_size._fields:\n",
    "            hidden_dim = getattr(cell._state_size, hidden_name)\n",
    "            h = self.initial_state(hidden_name, hidden_dim)\n",
    "            _states_0.append(h)\n",
    "\n",
    "        initial_state_cell = type(cell.state_size)(*_states_0)\n",
    "\n",
    "        return initial_state_cell\n",
    "\n",
    "\n",
    "    def initial_state(self, name, dim):\n",
    "        \"\"\"Returns initial state of dimension specified by dim\"\"\"\n",
    "        with tf.variable_scope(self._scope_name):\n",
    "            img_mean = tf.reduce_mean(self._img, axis=1)\n",
    "            W = tf.get_variable(\"W_{}_0\".format(name), shape=[self._n_channels,\n",
    "                    dim])\n",
    "            b = tf.get_variable(\"b_{}_0\".format(name), shape=[dim])\n",
    "            h = tf.tanh(tf.matmul(img_mean, W) + b)\n",
    "\n",
    "            return h"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# https://github.com/guillaumegenthial/im2latex/blob/master/model/components/attention_cell.py\n",
    "\n",
    "import collections\n",
    "from tensorflow.contrib.rnn import RNNCell, LSTMStateTuple\n",
    "\n",
    "\n",
    "AttentionState = collections.namedtuple(\"AttentionState\", (\"cell_state\", \"o\"))\n",
    "\n",
    "\n",
    "class AttentionCell(RNNCell):\n",
    "    def __init__(self, cell, attention_mechanism, dropout, dim_e,\n",
    "                 dim_o, num_units,\n",
    "        num_proj, dtype=tf.float32):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            cell: (RNNCell)\n",
    "            attention_mechanism: (AttentionMechanism)\n",
    "            dropout: (tf.float)\n",
    "            attn_cell_config: (dict) hyper params\n",
    "        \"\"\"\n",
    "        # variables and tensors\n",
    "        self._cell                = cell\n",
    "        self._attention_mechanism = attention_mechanism\n",
    "        self._dropout             = dropout\n",
    "\n",
    "        # hyperparameters and shapes\n",
    "        self._n_channels     = self._attention_mechanism._n_channels\n",
    "        self._dim_e          = dim_e\n",
    "        self._dim_o          = dim_o\n",
    "        self._num_units      = num_units\n",
    "        self._num_proj       = num_proj\n",
    "        self._dtype          = dtype\n",
    "\n",
    "        # for RNNCell\n",
    "        self._state_size = AttentionState(self._cell._state_size, self._dim_o)\n",
    "\n",
    "\n",
    "    @property\n",
    "    def state_size(self):\n",
    "        return self._state_size\n",
    "\n",
    "\n",
    "    @property\n",
    "    def output_size(self):\n",
    "        return self._num_proj\n",
    "\n",
    "\n",
    "    @property\n",
    "    def output_dtype(self):\n",
    "        return self._dtype\n",
    "\n",
    "\n",
    "    def initial_state(self):\n",
    "        \"\"\"Returns initial state for the lstm\"\"\"\n",
    "        initial_cell_state = self._attention_mechanism.initial_cell_state(self._cell)\n",
    "        initial_o          = self._attention_mechanism.initial_state(\"o\", self._dim_o)\n",
    "\n",
    "        return AttentionState(initial_cell_state, initial_o)\n",
    "\n",
    "\n",
    "    def step(self, embedding, attn_cell_state):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            embedding: shape = (batch_size, dim_embeddings) embeddings\n",
    "                from previous time step\n",
    "            attn_cell_state: (AttentionState) state from previous time step\n",
    "        \"\"\"\n",
    "        prev_cell_state, o = attn_cell_state\n",
    "\n",
    "        scope = tf.get_variable_scope()\n",
    "        with tf.variable_scope(scope):\n",
    "            # compute new h\n",
    "            x                     = tf.concat([embedding, o], axis=-1)\n",
    "            new_h, new_cell_state = self._cell.__call__(x, prev_cell_state)\n",
    "            new_h = tf.nn.dropout(new_h, self._dropout)\n",
    "\n",
    "            # compute attention\n",
    "            c = self._attention_mechanism.context(new_h)\n",
    "\n",
    "            # compute o\n",
    "            o_W_c = tf.get_variable(\"o_W_c\", dtype=tf.float32,\n",
    "                    shape=(self._n_channels, self._dim_o))\n",
    "            o_W_h = tf.get_variable(\"o_W_h\", dtype=tf.float32,\n",
    "                    shape=(self._num_units, self._dim_o))\n",
    "\n",
    "            new_o = tf.tanh(tf.matmul(new_h, o_W_h) + tf.matmul(c, o_W_c))\n",
    "            new_o = tf.nn.dropout(new_o, self._dropout)\n",
    "\n",
    "            y_W_o = tf.get_variable(\"y_W_o\", dtype=tf.float32,\n",
    "                    shape=(self._dim_o, self._num_proj))\n",
    "            logits = tf.matmul(new_o, y_W_o)\n",
    "\n",
    "            # new Attn cell state\n",
    "            new_state = AttentionState(new_cell_state, new_o)\n",
    "\n",
    "            return logits, new_state\n",
    "\n",
    "\n",
    "    def __call__(self, inputs, state):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            inputs: the embedding of the previous word for training only\n",
    "            state: (AttentionState) (h, o) where h is the hidden state and\n",
    "                o is the vector used to make the prediction of\n",
    "                the previous word\n",
    "        \"\"\"\n",
    "        new_output, new_state = self.step(inputs, state)\n",
    "\n",
    "        return (new_output, new_state)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import division\n",
    "import math\n",
    "import numpy as np\n",
    "from six.moves import xrange\n",
    "import tensorflow as tf\n",
    "\n",
    "\n",
    "# taken from https://github.com/tensorflow/tensor2tensor/blob/37465a1759e278e8f073cd04cd9b4fe377d3c740/tensor2tensor/layers/common_attention.py\n",
    "\n",
    "# taken from https://raw.githubusercontent.com/guillaumegenthial/im2latex/master/model/components/positional.py\n",
    "\n",
    "def add_timing_signal_nd(x, min_timescale=1.0, max_timescale=1.0e4):\n",
    "    \"\"\"Adds a bunch of sinusoids of different frequencies to a Tensor.\n",
    "\n",
    "    Each channel of the input Tensor is incremented by a sinusoid of a difft\n",
    "    frequency and phase in one of the positional dimensions.\n",
    "\n",
    "    This allows attention to learn to use absolute and relative positions.\n",
    "    Timing signals should be added to some precursors of both the query and the\n",
    "    memory inputs to attention.\n",
    "\n",
    "    The use of relative position is possible because sin(a+b) and cos(a+b) can\n",
    "    be experessed in terms of b, sin(a) and cos(a).\n",
    "\n",
    "    x is a Tensor with n \"positional\" dimensions, e.g. one dimension for a\n",
    "    sequence or two dimensions for an image\n",
    "\n",
    "    We use a geometric sequence of timescales starting with\n",
    "    min_timescale and ending with max_timescale.  The number of different\n",
    "    timescales is equal to channels // (n * 2). For each timescale, we\n",
    "    generate the two sinusoidal signals sin(timestep/timescale) and\n",
    "    cos(timestep/timescale).  All of these sinusoids are concatenated in\n",
    "    the channels dimension.\n",
    "\n",
    "    Args:\n",
    "        x: a Tensor with shape [batch, d1 ... dn, channels]\n",
    "        min_timescale: a float\n",
    "        max_timescale: a float\n",
    "\n",
    "    Returns:\n",
    "        a Tensor the same shape as x.\n",
    "\n",
    "    \"\"\"\n",
    "    static_shape = x.get_shape().as_list()\n",
    "    num_dims = len(static_shape) - 2\n",
    "    channels = tf.shape(x)[-1]\n",
    "    num_timescales = channels // (num_dims * 2)\n",
    "    log_timescale_increment = (\n",
    "            math.log(float(max_timescale) / float(min_timescale)) /\n",
    "            (tf.to_float(num_timescales) - 1))\n",
    "    inv_timescales = min_timescale * tf.exp(\n",
    "            tf.to_float(tf.range(num_timescales)) * -log_timescale_increment)\n",
    "    for dim in xrange(num_dims):\n",
    "        length = tf.shape(x)[dim + 1]\n",
    "        position = tf.to_float(tf.range(length))\n",
    "        scaled_time = tf.expand_dims(position, 1) * tf.expand_dims(\n",
    "                inv_timescales, 0)\n",
    "        signal = tf.concat([tf.sin(scaled_time), tf.cos(scaled_time)], axis=1)\n",
    "        prepad = dim * 2 * num_timescales\n",
    "        postpad = channels - (dim + 1) * 2 * num_timescales\n",
    "        signal = tf.pad(signal, [[0, 0], [prepad, postpad]])\n",
    "        for _ in xrange(1 + dim):\n",
    "            signal = tf.expand_dims(signal, 0)\n",
    "        for _ in xrange(num_dims - 1 - dim):\n",
    "            signal = tf.expand_dims(signal, -2)\n",
    "        x += signal\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "attention_size = 256\n",
    "size_layer = 512\n",
    "embedded_size = 256\n",
    "beam_width = 15\n",
    "learning_rate = 1e-4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "# CNN part I took from https://github.com/guillaumegenthial/im2latex/blob/master/model/encoder.py\n",
    "# I use tf.contrib.seq2seq as decoder part\n",
    "\n",
    "class Model:\n",
    "    def __init__(self):\n",
    "        self.X = tf.placeholder(tf.float32, shape=(None, 60, 240, 1))\n",
    "        self.Y = tf.placeholder(tf.int32, [None, None])\n",
    "        self.Y_seq_len = tf.count_nonzero(self.Y, 1, dtype=tf.int32)\n",
    "        batch_size = tf.shape(self.X)[0]\n",
    "        x_len = tf.shape(self.X)[2] // 2\n",
    "        main = tf.strided_slice(self.Y, [0, 0], [batch_size, -1], [1, 1])\n",
    "        decoder_input = tf.concat([tf.fill([batch_size, 1], GO), main], 1)\n",
    "        \n",
    "        decoder_embeddings = tf.Variable(tf.random_uniform([len(encode_maps), embedded_size], -1, 1))\n",
    "        \n",
    "        img = self.X\n",
    "        \n",
    "        out = tf.layers.conv2d(img, 64, 3, 1, \"SAME\",\n",
    "                activation=tf.nn.relu)\n",
    "        out = tf.layers.max_pooling2d(out, 2, 2, \"SAME\")\n",
    "\n",
    "        out = tf.layers.conv2d(out, 128, 3, 1, \"SAME\",\n",
    "                activation=tf.nn.relu)\n",
    "        out = tf.layers.max_pooling2d(out, 2, 2, \"SAME\")\n",
    "\n",
    "        out = tf.layers.conv2d(out, 256, 3, 1, \"SAME\",\n",
    "                activation=tf.nn.relu)\n",
    "\n",
    "        out = tf.layers.conv2d(out, 256, 3, 1, \"SAME\",\n",
    "                activation=tf.nn.relu)\n",
    "        out = tf.layers.max_pooling2d(out, (2, 1), (2, 1), \"SAME\")\n",
    "        out = tf.layers.conv2d(out, 512, 3, 1, \"SAME\",\n",
    "                activation=tf.nn.relu)\n",
    "        out = tf.layers.max_pooling2d(out, (1, 2), (1, 2), \"SAME\")\n",
    "        out = tf.layers.conv2d(out, 512, 3, 1, \"VALID\",\n",
    "                activation=tf.nn.relu)\n",
    "        img = add_timing_signal_nd(out)\n",
    "        print(img)\n",
    "        \n",
    "        with tf.variable_scope(\"attn_cell\", reuse=False):\n",
    "            attn_meca = AttentionMechanism(img, attention_size)\n",
    "            recu_cell = tf.nn.rnn_cell.LSTMCell(size_layer)\n",
    "            attn_cell = AttentionCell(recu_cell, attn_meca, 1.0,\n",
    "                        attention_size, attention_size, size_layer, len(encode_maps))\n",
    "\n",
    "            encoder_state = attn_cell.initial_state()\n",
    "\n",
    "            training_helper = tf.contrib.seq2seq.ScheduledEmbeddingTrainingHelper(\n",
    "                    inputs = tf.nn.embedding_lookup(decoder_embeddings, decoder_input),\n",
    "                    sequence_length = self.Y_seq_len,\n",
    "                    embedding = decoder_embeddings,\n",
    "                    sampling_probability = 0.5,\n",
    "                    time_major = False)\n",
    "            training_decoder = tf.contrib.seq2seq.BasicDecoder(\n",
    "                    cell = attn_cell,\n",
    "                    helper = training_helper,\n",
    "                    initial_state = encoder_state,\n",
    "                    output_layer = None)\n",
    "            training_decoder_output, _, _ = tf.contrib.seq2seq.dynamic_decode(\n",
    "                    decoder = training_decoder,\n",
    "                    impute_finished = True,\n",
    "                    maximum_iterations = tf.reduce_max(self.Y_seq_len))\n",
    "        \n",
    "        with tf.variable_scope(\"attn_cell\", reuse=True):\n",
    "            attn_meca = AttentionMechanism(img, attention_size, tiles=beam_width)\n",
    "            recu_cell = tf.nn.rnn_cell.LSTMCell(size_layer, reuse = True)\n",
    "            attn_cell = AttentionCell(recu_cell, attn_meca, 1.0,\n",
    "                        attention_size, attention_size, size_layer, len(encode_maps))\n",
    "            \n",
    "            encoder_state = attn_cell.initial_state()\n",
    "            \n",
    "            predicting_decoder = tf.contrib.seq2seq.BeamSearchDecoder(\n",
    "                cell = attn_cell,\n",
    "                embedding = decoder_embeddings,\n",
    "                start_tokens = tf.tile(tf.constant([GO], dtype=tf.int32), [batch_size]),\n",
    "                end_token = EOS,\n",
    "                initial_state = tf.contrib.seq2seq.tile_batch(encoder_state, beam_width),\n",
    "                beam_width = beam_width,\n",
    "                output_layer = None,\n",
    "                length_penalty_weight = 0.0)\n",
    "            predicting_decoder_output, _, _ = tf.contrib.seq2seq.dynamic_decode(\n",
    "                decoder = predicting_decoder,\n",
    "                impute_finished = False,\n",
    "                maximum_iterations = x_len)\n",
    "            \n",
    "        self.training_logits = training_decoder_output.rnn_output\n",
    "        self.predicting_ids = predicting_decoder_output.predicted_ids\n",
    "        self.predicting_ids = tf.identity(self.predicting_ids, name = 'logits')\n",
    "        \n",
    "        masks = tf.sequence_mask(self.Y_seq_len, tf.reduce_max(self.Y_seq_len), dtype=tf.float32)\n",
    "        self.cost = tf.contrib.seq2seq.sequence_loss(logits = self.training_logits,\n",
    "                                                     targets = self.Y,\n",
    "                                                     weights = masks)\n",
    "        self.optimizer = tf.train.AdamOptimizer(learning_rate).minimize(self.cost)\n",
    "        y_t = tf.argmax(self.training_logits,axis=2)\n",
    "        y_t = tf.cast(y_t, tf.int32)\n",
    "        self.prediction = tf.boolean_mask(y_t, masks)\n",
    "        mask_label = tf.boolean_mask(self.Y, masks)\n",
    "        correct_pred = tf.equal(self.prediction, mask_label)\n",
    "        correct_index = tf.cast(correct_pred, tf.float32)\n",
    "        self.accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/husein/.local/lib/python3.6/site-packages/tensorflow/python/client/session.py:1735: UserWarning: An interactive session is already active. This can cause out-of-memory errors in some cases. You must explicitly call `InteractiveSession.close()` to release resources held by the other session(s).\n",
      "  warnings.warn('An interactive session is already active. This can '\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tensor(\"add_1:0\", shape=(?, 6, 28, 512), dtype=float32)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/husein/.local/lib/python3.6/site-packages/tensorflow/python/ops/gradients_util.py:93: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "  \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n"
     ]
    }
   ],
   "source": [
    "tf.reset_default_graph()\n",
    "sess = tf.InteractiveSession()\n",
    "model = Model()\n",
    "sess.run(tf.global_variables_initializer())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Placeholder',\n",
       " 'Placeholder_1',\n",
       " 'Variable',\n",
       " 'conv2d/kernel',\n",
       " 'conv2d/bias',\n",
       " 'conv2d_1/kernel',\n",
       " 'conv2d_1/bias',\n",
       " 'conv2d_2/kernel',\n",
       " 'conv2d_2/bias',\n",
       " 'conv2d_3/kernel',\n",
       " 'conv2d_3/bias',\n",
       " 'conv2d_4/kernel',\n",
       " 'conv2d_4/bias',\n",
       " 'conv2d_5/kernel',\n",
       " 'conv2d_5/bias',\n",
       " 'attn_cell/att_img/kernel',\n",
       " 'attn_cell/att_mechanism/W_c_0',\n",
       " 'attn_cell/att_mechanism/b_c_0',\n",
       " 'attn_cell/att_mechanism/W_h_0',\n",
       " 'attn_cell/att_mechanism/b_h_0',\n",
       " 'attn_cell/att_mechanism/W_o_0',\n",
       " 'attn_cell/att_mechanism/b_o_0',\n",
       " 'attn_cell/decoder/lstm_cell/kernel',\n",
       " 'attn_cell/decoder/lstm_cell/bias',\n",
       " 'attn_cell/decoder/att_mechanism/dense/kernel',\n",
       " 'attn_cell/decoder/o_W_c',\n",
       " 'attn_cell/decoder/o_W_h',\n",
       " 'attn_cell/decoder/y_W_o',\n",
       " 'logits']"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "strings = ','.join(\n",
    "    [\n",
    "        n.name\n",
    "        for n in tf.get_default_graph().as_graph_def().node\n",
    "        if ('Variable' in n.op\n",
    "        or 'Placeholder' in n.name\n",
    "        or 'logits' in n.name\n",
    "        or 'alphas' in n.name\n",
    "        or 'self/Softmax' in n.name)\n",
    "        and 'adam' not in n.name\n",
    "        and 'Adam' not in n.name\n",
    "        and 'beta' not in n.name\n",
    "        and 'global_step' not in n.name\n",
    "    ]\n",
    ")\n",
    "strings.split(',')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'im2latex/model.ckpt'"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "saver = tf.train.Saver(tf.trainable_variables())\n",
    "saver.save(sess, 'im2latex/model.ckpt')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "def freeze_graph(model_dir, output_node_names):\n",
    "\n",
    "    if not tf.gfile.Exists(model_dir):\n",
    "        raise AssertionError(\n",
    "            \"Export directory doesn't exists. Please specify an export \"\n",
    "            'directory: %s' % model_dir\n",
    "        )\n",
    "\n",
    "    checkpoint = tf.train.get_checkpoint_state(model_dir)\n",
    "    input_checkpoint = checkpoint.model_checkpoint_path\n",
    "\n",
    "    absolute_model_dir = '/'.join(input_checkpoint.split('/')[:-1])\n",
    "    output_graph = absolute_model_dir + '/frozen_model.pb'\n",
    "    clear_devices = True\n",
    "    with tf.Session(graph = tf.Graph()) as sess:\n",
    "        saver = tf.train.import_meta_graph(\n",
    "            input_checkpoint + '.meta', clear_devices = clear_devices\n",
    "        )\n",
    "        saver.restore(sess, input_checkpoint)\n",
    "        output_graph_def = tf.graph_util.convert_variables_to_constants(\n",
    "            sess,\n",
    "            tf.get_default_graph().as_graph_def(),\n",
    "            output_node_names.split(','),\n",
    "        )\n",
    "        with tf.gfile.GFile(output_graph, 'wb') as f:\n",
    "            f.write(output_graph_def.SerializeToString())\n",
    "        print('%d ops in the final graph.' % len(output_graph_def.node))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:tensorflow:Restoring parameters from im2latex/model.ckpt\n",
      "INFO:tensorflow:Froze 27 variables.\n",
      "INFO:tensorflow:Converted 27 variables to const ops.\n",
      "805 ops in the final graph.\n"
     ]
    }
   ],
   "source": [
    "freeze_graph('im2latex', strings)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor 'attn_cell/decoder/transpose:0' shape=(?, ?, 33) dtype=float32>"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.training_logits"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "def pad_sentence_batch(sentence_batch, pad_int):\n",
    "    padded_seqs = []\n",
    "    seq_lens = []\n",
    "    max_sentence_len = max([len(sentence) for sentence in sentence_batch])\n",
    "    for sentence in sentence_batch:\n",
    "        padded_seqs.append(sentence + [pad_int] * (max_sentence_len - len(sentence)))\n",
    "        seq_lens.append(len(sentence))\n",
    "    return padded_seqs, seq_lens"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3.68607, 0.0)"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "batch_x = train_X[:5]\n",
    "batch_x = np.array(batch_x).reshape((len(batch_x), image_height, image_width,image_channel))\n",
    "y = train_Y[:5]\n",
    "batch_y, _ = pad_sentence_batch(y, 0)\n",
    "loss, logits, acc = sess.run([model.cost, model.training_logits, model.accuracy], feed_dict = {model.X: batch_x,\n",
    "                                                          model.Y: batch_y})\n",
    "loss, acc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(5, 120, 15)"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "batch_x = train_X[:5]\n",
    "batch_x = np.array(batch_x).reshape((len(batch_x), image_height, image_width,image_channel))\n",
    "y = train_Y[:5]\n",
    "batch_y, _ = pad_sentence_batch(y, 0)\n",
    "logits = sess.run(model.predicting_ids, feed_dict = {model.X: batch_x})\n",
    "logits.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "minibatch loop: 100%|██████████| 507/507 [01:32<00:00,  5.51it/s, accuracy=0.972, cost=0.0901]\n",
      "minibatch loop: 100%|██████████| 127/127 [00:10<00:00, 12.59it/s, accuracy=0.878, cost=0.437]\n",
      "minibatch loop:   0%|          | 1/507 [00:00<01:29,  5.68it/s, accuracy=0.949, cost=0.156]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 1, training avg loss 0.152301, training avg acc 0.951534\n",
      "epoch 1, testing avg loss 0.412375, testing avg acc 0.886601\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "minibatch loop: 100%|██████████| 507/507 [01:31<00:00,  5.52it/s, accuracy=0.973, cost=0.0828]\n",
      "minibatch loop: 100%|██████████| 127/127 [00:09<00:00, 12.75it/s, accuracy=0.882, cost=0.463]\n",
      "minibatch loop:   0%|          | 1/507 [00:00<01:28,  5.69it/s, accuracy=0.949, cost=0.149]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 2, training avg loss 0.147481, training avg acc 0.953340\n",
      "epoch 2, testing avg loss 0.399478, testing avg acc 0.887377\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "minibatch loop: 100%|██████████| 507/507 [01:31<00:00,  5.51it/s, accuracy=0.954, cost=0.163] \n",
      "minibatch loop: 100%|██████████| 127/127 [00:10<00:00, 12.61it/s, accuracy=0.885, cost=0.439]\n",
      "minibatch loop:   0%|          | 1/507 [00:00<01:27,  5.76it/s, accuracy=0.944, cost=0.185]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 3, training avg loss 0.139094, training avg acc 0.955725\n",
      "epoch 3, testing avg loss 0.450588, testing avg acc 0.873517\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "minibatch loop: 100%|██████████| 507/507 [01:31<00:00,  5.52it/s, accuracy=0.974, cost=0.0827]\n",
      "minibatch loop: 100%|██████████| 127/127 [00:10<00:00, 12.55it/s, accuracy=0.872, cost=0.46] \n",
      "minibatch loop:   0%|          | 1/507 [00:00<01:30,  5.57it/s, accuracy=0.942, cost=0.179]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 4, training avg loss 0.133433, training avg acc 0.957887\n",
      "epoch 4, testing avg loss 0.446984, testing avg acc 0.876499\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "minibatch loop: 100%|██████████| 507/507 [01:31<00:00,  5.51it/s, accuracy=0.982, cost=0.0629]\n",
      "minibatch loop: 100%|██████████| 127/127 [00:10<00:00, 12.58it/s, accuracy=0.897, cost=0.451]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 5, training avg loss 0.125402, training avg acc 0.960689\n",
      "epoch 5, testing avg loss 0.405598, testing avg acc 0.888860\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "import tqdm\n",
    "\n",
    "for e in range(5):\n",
    "    pbar = tqdm.tqdm(\n",
    "        range(0, len(train_X), batch_size), desc = 'minibatch loop')\n",
    "    train_loss, train_acc, test_loss, test_acc = [], [], [], []\n",
    "    for i in pbar:\n",
    "        index = min(i + batch_size, len(train_X))\n",
    "        batch_x = train_X[i : index]\n",
    "        batch_x = np.array(batch_x).reshape((len(batch_x), image_height, image_width,image_channel))\n",
    "        y = train_Y[i : index]\n",
    "        batch_y, _ = pad_sentence_batch(y, 0)\n",
    "        feed = {model.X: batch_x,\n",
    "                model.Y: batch_y}\n",
    "        accuracy, loss, _ = sess.run([model.accuracy,model.cost,model.optimizer],\n",
    "                                    feed_dict = feed)\n",
    "        train_loss.append(loss)\n",
    "        train_acc.append(accuracy)\n",
    "        pbar.set_postfix(cost = loss, accuracy = accuracy)\n",
    "    \n",
    "    \n",
    "    pbar = tqdm.tqdm(\n",
    "        range(0, len(test_X), batch_size), desc = 'minibatch loop')\n",
    "    for i in pbar:\n",
    "        index = min(i + batch_size, len(test_X))\n",
    "        batch_x = test_X[i : index]\n",
    "        batch_x = np.array(batch_x).reshape((len(batch_x), image_height, image_width,image_channel))\n",
    "        y = test_Y[i : index]\n",
    "        batch_y, _ = pad_sentence_batch(y, 0)\n",
    "        feed = {model.X: batch_x,\n",
    "                model.Y: batch_y,}\n",
    "        accuracy, loss = sess.run([model.accuracy,model.cost],\n",
    "                                    feed_dict = feed)\n",
    "\n",
    "        test_loss.append(loss)\n",
    "        test_acc.append(accuracy)\n",
    "        pbar.set_postfix(cost = loss, accuracy = accuracy)\n",
    "    \n",
    "    print('epoch %d, training avg loss %f, training avg acc %f'%(e+1,\n",
    "                                                                 np.mean(train_loss),np.mean(train_acc)))\n",
    "    print('epoch %d, testing avg loss %f, testing avg acc %f'%(e+1,\n",
    "                                                              np.mean(test_loss),np.mean(test_acc)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:tensorflow:Restoring parameters from im2latex/model.ckpt\n",
      "INFO:tensorflow:Froze 27 variables.\n",
      "INFO:tensorflow:Converted 27 variables to const ops.\n",
      "805 ops in the final graph.\n"
     ]
    }
   ],
   "source": [
    "saver.save(sess, 'im2latex/model.ckpt')\n",
    "freeze_graph('im2latex', strings)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(16, 15)"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "decoded = sess.run(model.predicting_ids, feed_dict = {model.X: batch_x[:1]})[0]\n",
    "decoded.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n",
      "abad sehingga\n"
     ]
    }
   ],
   "source": [
    "for i in range(decoded.shape[1]):\n",
    "    d = decoded[:,0]\n",
    "    print(''.join([decode_maps[i] for i in d if i not in [0,1,2]]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(cv2.flip(batch_x[0][:,:,0], 1))\n",
    "decoded = ''.join([decode_maps[i] for i in decoded[:,0] if i not in [0,1,2]])\n",
    "actual = ''.join([decode_maps[i] for i in batch_y[0] if i not in [0,1,2]])\n",
    "plt.title('predict: %s, actual: %s'%(decoded, actual))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "def load_graph(frozen_graph_filename):\n",
    "    with tf.gfile.GFile(frozen_graph_filename, 'rb') as f:\n",
    "        graph_def = tf.GraphDef()\n",
    "        graph_def.ParseFromString(f.read())\n",
    "    with tf.Graph().as_default() as graph:\n",
    "        tf.import_graph_def(graph_def)\n",
    "    return graph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [],
   "source": [
    "g = load_graph('im2latex/frozen_model.pb')\n",
    "x = g.get_tensor_by_name('import/Placeholder:0')\n",
    "logits = g.get_tensor_by_name('import/logits:0')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/husein/.local/lib/python3.6/site-packages/tensorflow/python/client/session.py:1735: UserWarning: An interactive session is already active. This can cause out-of-memory errors in some cases. You must explicitly call `InteractiveSession.close()` to release resources held by the other session(s).\n",
      "  warnings.warn('An interactive session is already active. This can '\n"
     ]
    }
   ],
   "source": [
    "test_sess = tf.InteractiveSession(graph = g)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(21, 15)"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "decoded = test_sess.run(logits, feed_dict = {x: batch_x[10:11]})[0]\n",
    "decoded.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n",
      "betina sesetengah\n"
     ]
    }
   ],
   "source": [
    "for i in range(decoded.shape[1]):\n",
    "    d = decoded[:,0]\n",
    "    print(''.join([decode_maps[i] for i in d if i not in [0,1,2]]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(cv2.flip(batch_x[10][:,:,0], 1))\n",
    "decoded = ''.join([decode_maps[i] for i in decoded[:,0] if i not in [0,1,2]])\n",
    "actual = ''.join([decode_maps[i] for i in batch_y[10] if i not in [0,1,2]])\n",
    "plt.title('predict: %s, actual: %s'%(decoded, actual))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
